using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Globalization;
using System.Linq;
using System.Runtime.CompilerServices;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Serialization;
using ns16;
using ns20;

namespace Newtonsoft.Json.Schema
{
	public class JsonSchemaGenerator
	{
		private class Class134
		{
			[CompilerGenerated]
			private Type type_0;

			[CompilerGenerated]
			private JsonSchema jsonSchema_0;

			public Type Type_0
			{
				[CompilerGenerated]
				get
				{
					return type_0;
				}
				[CompilerGenerated]
				private set
				{
					type_0 = value;
				}
			}

			public JsonSchema JsonSchema_0
			{
				[CompilerGenerated]
				get
				{
					return jsonSchema_0;
				}
				[CompilerGenerated]
				private set
				{
					jsonSchema_0 = value;
				}
			}

			public Class134(Type type, JsonSchema schema)
			{
				Class204.smethod_2(type, "type");
				Class204.smethod_2(schema, "schema");
				Type_0 = type;
				JsonSchema_0 = schema;
			}
		}

		[CompilerGenerated]
		private sealed class Class135
		{
			public Type type_0;

			public bool method_0(Class134 class134_0)
			{
				return class134_0.Type_0 == type_0;
			}
		}

		private IContractResolver icontractResolver_0;

		private JsonSchemaResolver jsonSchemaResolver_0;

		private readonly IList<Class134> ilist_0 = new List<Class134>();

		private JsonSchema jsonSchema_0;

		[CompilerGenerated]
		private UndefinedSchemaIdHandling undefinedSchemaIdHandling_0;

		public UndefinedSchemaIdHandling UndefinedSchemaIdHandling
		{
			[CompilerGenerated]
			get
			{
				return undefinedSchemaIdHandling_0;
			}
			[CompilerGenerated]
			set
			{
				undefinedSchemaIdHandling_0 = value;
			}
		}

		public IContractResolver ContractResolver
		{
			get
			{
				if (icontractResolver_0 == null)
				{
					return DefaultContractResolver.IContractResolver_0;
				}
				return icontractResolver_0;
			}
			set
			{
				icontractResolver_0 = value;
			}
		}

		private JsonSchema JsonSchema_0 => jsonSchema_0;

		private void method_0(Class134 class134_0)
		{
			jsonSchema_0 = class134_0.JsonSchema_0;
			ilist_0.Add(class134_0);
			jsonSchemaResolver_0.LoadedSchemas.Add(class134_0.JsonSchema_0);
		}

		private Class134 method_1()
		{
			Class134 result = ilist_0[ilist_0.Count - 1];
			ilist_0.RemoveAt(ilist_0.Count - 1);
			Class134 @class = ilist_0.LastOrDefault();
			if (@class != null)
			{
				jsonSchema_0 = @class.JsonSchema_0;
			}
			else
			{
				jsonSchema_0 = null;
			}
			return result;
		}

		public JsonSchema Generate(Type type)
		{
			return Generate(type, new JsonSchemaResolver(), rootSchemaNullable: false);
		}

		public JsonSchema Generate(Type type, JsonSchemaResolver resolver)
		{
			return Generate(type, resolver, rootSchemaNullable: false);
		}

		public JsonSchema Generate(Type type, bool rootSchemaNullable)
		{
			return Generate(type, new JsonSchemaResolver(), rootSchemaNullable);
		}

		public JsonSchema Generate(Type type, JsonSchemaResolver resolver, bool rootSchemaNullable)
		{
			Class204.smethod_2(type, "type");
			Class204.smethod_2(resolver, "resolver");
			jsonSchemaResolver_0 = resolver;
			return method_5(type, (!rootSchemaNullable) ? Required.Always : Required.Default, bool_0: false);
		}

		private string method_2(Type type_0)
		{
			JsonContainerAttribute jsonContainerAttribute = Class140.smethod_0(type_0);
			if (jsonContainerAttribute != null && !string.IsNullOrEmpty(jsonContainerAttribute.Title))
			{
				return jsonContainerAttribute.Title;
			}
			return null;
		}

		private string method_3(Type type_0)
		{
			JsonContainerAttribute jsonContainerAttribute = Class140.smethod_0(type_0);
			if (jsonContainerAttribute != null && !string.IsNullOrEmpty(jsonContainerAttribute.Description))
			{
				return jsonContainerAttribute.Description;
			}
			return Class195.smethod_29<DescriptionAttribute>(type_0)?.Description;
		}

		private string method_4(Type type_0, bool bool_0)
		{
			JsonContainerAttribute jsonContainerAttribute = Class140.smethod_0(type_0);
			if (jsonContainerAttribute != null && !string.IsNullOrEmpty(jsonContainerAttribute.Id))
			{
				return jsonContainerAttribute.Id;
			}
			if (bool_0)
			{
				return null;
			}
			return UndefinedSchemaIdHandling switch
			{
				UndefinedSchemaIdHandling.UseTypeName => type_0.FullName, 
				UndefinedSchemaIdHandling.UseAssemblyQualifiedName => type_0.AssemblyQualifiedName, 
				_ => null, 
			};
		}

		private JsonSchema method_5(Type type_0, Required required_0, bool bool_0)
		{
			Class204.smethod_2(type_0, "type");
			string text = method_4(type_0, bool_0: false);
			string text2 = method_4(type_0, bool_0: true);
			if (!string.IsNullOrEmpty(text))
			{
				JsonSchema schema = jsonSchemaResolver_0.GetSchema(text);
				if (schema != null)
				{
					if (required_0 != Required.Always && !smethod_0(schema.Type, JsonSchemaType.Null))
					{
						schema.Type |= JsonSchemaType.Null;
					}
					if (bool_0 && schema.Required != true)
					{
						schema.Required = true;
					}
					return schema;
				}
			}
			if (ilist_0.Any((Class134 class134_0) => class134_0.Type_0 == type_0))
			{
				throw new JsonException("Unresolved circular reference for type '{0}'. Explicitly define an Id for the type using a JsonObject/JsonArray attribute or automatically generate a type Id using the UndefinedSchemaIdHandling property.".smethod_0(CultureInfo.InvariantCulture, type_0));
			}
			JsonContract jsonContract = ContractResolver.ResolveContract(type_0);
			JsonConverter jsonConverter;
			if ((jsonConverter = jsonContract.Converter) != null || (jsonConverter = jsonContract.JsonConverter_0) != null)
			{
				JsonSchema schema2 = jsonConverter.GetSchema();
				if (schema2 != null)
				{
					return schema2;
				}
			}
			method_0(new Class134(type_0, new JsonSchema()));
			if (text2 != null)
			{
				JsonSchema_0.Id = text2;
			}
			if (bool_0)
			{
				JsonSchema_0.Required = true;
			}
			JsonSchema_0.Title = method_2(type_0);
			JsonSchema_0.Description = method_3(type_0);
			if (jsonConverter != null)
			{
				JsonSchema_0.Type = JsonSchemaType.Any;
			}
			else
			{
				switch (jsonContract.enum15_0)
				{
				default:
					throw new JsonException("Unexpected contract type: {0}".smethod_0(CultureInfo.InvariantCulture, jsonContract));
				case Enum15.Object:
					JsonSchema_0.Type = method_6(JsonSchemaType.Object, required_0);
					JsonSchema_0.Id = method_4(type_0, bool_0: false);
					method_8(type_0, (JsonObjectContract)jsonContract);
					break;
				case Enum15.Array:
				{
					JsonSchema_0.Type = method_6(JsonSchemaType.Array, required_0);
					JsonSchema_0.Id = method_4(type_0, bool_0: false);
					bool flag = (Class140.smethod_0(type_0) as JsonArrayAttribute)?.AllowNullItems ?? true;
					Type type = Class195.smethod_18(type_0);
					if (type != null)
					{
						JsonSchema_0.Items = new List<JsonSchema>();
						JsonSchema_0.Items.Add(method_5(type, (!flag) ? Required.Always : Required.Default, bool_0: false));
					}
					break;
				}
				case Enum15.Primitive:
				{
					JsonSchema_0.Type = method_10(type_0, required_0);
					if (JsonSchema_0.Type != JsonSchemaType.Integer || !type_0.smethod_7() || type_0.IsDefined(typeof(FlagsAttribute), inherit: true))
					{
						break;
					}
					JsonSchema_0.Enum = new List<JToken>();
					Class189<long> @class = Class187.smethod_2<long>(type_0);
					foreach (Class188<long> item2 in @class)
					{
						JToken item = JToken.FromObject(item2.Prop_0);
						JsonSchema_0.Enum.Add(item);
					}
					break;
				}
				case Enum15.String:
				{
					JsonSchemaType value = ((!Class195.smethod_9(jsonContract.UnderlyingType)) ? JsonSchemaType.String : method_6(JsonSchemaType.String, required_0));
					JsonSchema_0.Type = value;
					break;
				}
				case Enum15.Dictionary:
				{
					JsonSchema_0.Type = method_6(JsonSchemaType.Object, required_0);
					Class195.smethod_19(type_0, out var type_, out var type_2);
					if (type_ != null)
					{
						JsonContract jsonContract2 = ContractResolver.ResolveContract(type_);
						if (jsonContract2.enum15_0 == Enum15.Primitive)
						{
							JsonSchema_0.AdditionalProperties = method_5(type_2, Required.Default, bool_0: false);
						}
					}
					break;
				}
				case Enum15.Serializable:
					JsonSchema_0.Type = method_6(JsonSchemaType.Object, required_0);
					JsonSchema_0.Id = method_4(type_0, bool_0: false);
					method_9(type_0, (JsonISerializableContract)jsonContract);
					break;
				case Enum15.Dynamic:
				case Enum15.Linq:
					JsonSchema_0.Type = JsonSchemaType.Any;
					break;
				}
			}
			return method_1().JsonSchema_0;
		}

		private JsonSchemaType method_6(JsonSchemaType jsonSchemaType_0, Required required_0)
		{
			if (required_0 != Required.Always)
			{
				return jsonSchemaType_0 | JsonSchemaType.Null;
			}
			return jsonSchemaType_0;
		}

		private bool method_7(DefaultValueHandling defaultValueHandling_0, DefaultValueHandling defaultValueHandling_1)
		{
			return (defaultValueHandling_0 & defaultValueHandling_1) == defaultValueHandling_1;
		}

		private void method_8(Type type_0, JsonObjectContract jsonObjectContract_0)
		{
			JsonSchema_0.Properties = new Dictionary<string, JsonSchema>();
			foreach (JsonProperty property in jsonObjectContract_0.Properties)
			{
				if (!property.Ignored)
				{
					bool flag = property.NullValueHandling == NullValueHandling.Ignore || method_7(property.DefaultValueHandling.GetValueOrDefault(), DefaultValueHandling.Ignore) || property.ShouldSerialize != null || property.GetIsSpecified != null;
					JsonSchema jsonSchema = method_5(property.PropertyType, property.Required, !flag);
					if (property.DefaultValue != null)
					{
						jsonSchema.Default = JToken.FromObject(property.DefaultValue);
					}
					JsonSchema_0.Properties.Add(property.PropertyName, jsonSchema);
				}
			}
			if (type_0.smethod_9())
			{
				JsonSchema_0.AllowAdditionalProperties = false;
			}
		}

		private void method_9(Type type_0, JsonISerializableContract jsonISerializableContract_0)
		{
			JsonSchema_0.AllowAdditionalProperties = true;
		}

		internal static bool smethod_0(JsonSchemaType? nullable_0, JsonSchemaType jsonSchemaType_0)
		{
			if (!nullable_0.HasValue)
			{
				return true;
			}
			if ((nullable_0 & jsonSchemaType_0) == jsonSchemaType_0)
			{
				return true;
			}
			if (nullable_0 == JsonSchemaType.Float && jsonSchemaType_0 == JsonSchemaType.Integer)
			{
				return true;
			}
			return false;
		}

		private JsonSchemaType method_10(Type type_0, Required required_0)
		{
			JsonSchemaType jsonSchemaType = JsonSchemaType.None;
			if (required_0 != Required.Always && Class195.smethod_9(type_0))
			{
				jsonSchemaType = JsonSchemaType.Null;
				if (Class195.smethod_10(type_0))
				{
					type_0 = Nullable.GetUnderlyingType(type_0);
				}
			}
			Enum17 @enum = Class182.smethod_0(type_0);
			switch (@enum)
			{
			case Enum17.Empty:
			case Enum17.Object:
				return jsonSchemaType | JsonSchemaType.String;
			case Enum17.Char:
				return jsonSchemaType | JsonSchemaType.String;
			case Enum17.Boolean:
				return jsonSchemaType | JsonSchemaType.Boolean;
			case Enum17.DateTime:
			case Enum17.DateTimeOffset:
				return jsonSchemaType | JsonSchemaType.String;
			case Enum17.Single:
			case Enum17.Double:
			case Enum17.Decimal:
				return jsonSchemaType | JsonSchemaType.Float;
			case Enum17.SByte:
			case Enum17.Int16:
			case Enum17.UInt16:
			case Enum17.Int32:
			case Enum17.Byte:
			case Enum17.UInt32:
			case Enum17.Int64:
			case Enum17.UInt64:
			case Enum17.BigInteger:
				return jsonSchemaType | JsonSchemaType.Integer;
			default:
				throw new JsonException("Unexpected type code '{0}' for type '{1}'.".smethod_1(CultureInfo.InvariantCulture, @enum, type_0));
			case Enum17.Guid:
			case Enum17.TimeSpan:
			case Enum17.Uri:
			case Enum17.String:
			case Enum17.Bytes:
				return jsonSchemaType | JsonSchemaType.String;
			case Enum17.DBNull:
				return jsonSchemaType | JsonSchemaType.Null;
			}
		}
	}
}
